package com.qqn.acknowledge.reflection;



import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

/**
 * @ClassName: Container
 * @Description: 负责注册服务和获得实例
 * @Author: 刘神仙
 * @Date: 2025-03-26 07:42
 */
public class Container {
    // 存放的是方法本身，而不是方法执行后获得的实例，具体的实例将在使用时
    // 执行这些方法来获取，这种做法可以节省资源并提高性能
    private Map<Class<?>, Method> methods;
    // 存放 Config 实例，之后用来调用方法来获得服务实例
    private Object config;
    // 创建一个类型为 Map 集合的字段来存储已经创建的实例
    private Map<Class<?>, Object> services;

    public void init() throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
        // 初始化 methods
        this.methods = new HashMap<>();
        this.services = new HashMap<>();
        Class<?> clazz = Class.forName("com.qqn.acknowledge.reflection.Config");
        Method[] methods = clazz.getDeclaredMethods();
        for (Method method : methods) {
            if (method.getDeclaredAnnotation(Bean.class) != null) {
                this.methods.put(method.getReturnType(), method);
            }
        }
        // 实例化 Config 对象 用来之后调用方法获得服务对象
        this.config = clazz.getConstructor().newInstance();
    }

    // 通过类的 Class 对象获取相应的服务实例，命名为 getServiceInstanceByClass
    // 获取构造器 参数的实例
    public Object getServiceInstanceByClass(Class<?> clazz) throws InvocationTargetException, IllegalAccessException {
        if (services.containsKey(clazz)) {
            return this.services.get(clazz);
        } else {
            if (this.methods.containsKey(clazz)) {
                // 执行该方法后确实获得了一个对象实例，但是这里出现了一个问题
                // 每次调用这个方法以获取服务实例时都会重新创建一个新对象，这在性能上可能会引起问题
                // 因为很多服务都是全局的，需要在很多地方使用，我们不希望每次都创建新的服务对象
                // 理想的做法是创建一次之后就复用这个实例
                Method method = this.methods.get(clazz);
                Object obj = method.invoke(this.config);
                this.services.put(clazz, obj);
                return obj;
            }
        }
        return null;
    }

    // 通过 Class 对象创建普通实例，并且实现将服务自动注入到对象里面
    // 使用注解来获取特定的构造器，并通过够造器的参数，自动将服务注入到实例当中
    public Object createInstance(Class<?> clazz) throws InvocationTargetException, IllegalAccessException, InstantiationException, NoSuchMethodException {
        Constructor<?>[] constructors = clazz.getDeclaredConstructors();
        for (Constructor<?> constructor : constructors) {
            // 通过带参数构造器实例化对象
            if (constructor.getDeclaredAnnotation(Autowired.class) != null) {
                // 获得构造器所有的参数类型
                Class<?>[] parameterTypes = constructor.getParameterTypes();
                // 创建一个对象数组，用于存放参数类型的对应的实例
                Object[] arguments = new Object[parameterTypes.length];
                for (int i = 0; i < arguments.length; i++) {
                    arguments[i] = getServiceInstanceByClass(parameterTypes[i]);
                }
                return constructor.newInstance(arguments); // 创建 Order 的实例
            }
        }
        return clazz.getDeclaredConstructor().newInstance();
    }
}
